#include <fstream>
#include <istream>
#include <ostream>
#include <iostream>
#include <cmath>

#include "Bitmap.h"
#include "Palette.h"
#include "SmartArray.h"

void Bitmap::ExportToFile( std::ostream& blob )
{
	blob.write((char*)FileHeader.mMagic,2);
	blob.write((char*)&FileHeader.mFileSize,4);
	blob.write((char*)FileHeader.mReserve,2*2);
	blob.write((char*)&FileHeader.mRelativePixels,4);
	blob.write((char*)&Header.mHeaderSize,4);
	blob.write((char*)&Header.mWidth,4);
	blob.write((char*)&Header.mHeight,4);
	blob.write((char*)&Header.mNumPlanes,2);
	blob.write((char*)&Header.mBPP,2);
	blob.write((char*)&Header.mCompressionMethod,4);
	blob.write((char*)&Header.mImageDataSize,4);
	blob.write((char*)Header.mPixelsPerMeter,4*2);
	blob.write((char*)Header.mColorDetails,4*2);
	for(unsigned int i=0,end=Palettes.Length(); i<end; i++)
		Palettes[i].ExportToFile(blob);
	blob.write(pixelData,Header.mImageDataSize);
}
void Bitmap::LoadFromFile( std::istream& blob)
{
	blob.read((char*)FileHeader.mMagic,2);
	blob.read((char*)&FileHeader.mFileSize,4);
	blob.read((char*)FileHeader.mReserve,2*2);
	blob.read((char*)&FileHeader.mRelativePixels,4);
	blob.read((char*)&Header.mHeaderSize,4);
	blob.read((char*)&Header.mWidth,4);
	blob.read((char*)&Header.mHeight,4);
	blob.read((char*)&Header.mNumPlanes,2);
	blob.read((char*)&Header.mBPP,2);
	blob.read((char*)&Header.mCompressionMethod,4);
	blob.read((char*)&Header.mImageDataSize,4);
	blob.read((char*)Header.mPixelsPerMeter,4*2);
	blob.read((char*)Header.mColorDetails,4*2);
	unsigned int numColors = static_cast<unsigned int>(pow( 2.0, Header.mBPP));
	if(!(FileHeader.mMagic[0] == 'B' && FileHeader.mMagic[1] == 'M' ))
		throw std::runtime_error("File-magic test failed.");
	if( Header.mBPP > 8 )
		throw std::runtime_error("Bitmap is non-indexed!");
	for( unsigned int i=0,end=numColors/16; i<end; i++)
	{
		Palette* pal = new Palette("BITMAP...");
		unsigned int col;
		for(unsigned int i=0; i<16; i++)
		{
			blob.read((char*)&col,4),(*pal)[i]=col;
		}
		Palettes.Append(pal);
	}
	blob.read(pixelData=new char[Header.mImageDataSize],Header.mImageDataSize);
}
Bitmap::Bitmap( const char* fn )
{
	memset( &FileHeader, 0x00, sizeof(FileHeader));
	memset( &Header, 0x00, sizeof(Header));
	std::ifstream input(fn,std::ios::in|std::ios::binary);
	LoadFromFile(input);
}
Bitmap::Bitmap()
{
	memset( &FileHeader, 0x00, sizeof(FileHeader));
	memset( &Header, 0x00, sizeof(Header));
}
Bitmap::~Bitmap()
{
	if(pixelData) delete pixelData;
}
Palette& Bitmap::GetPalette( int indice )
{
	return Palettes[indice];
}
unsigned int Bitmap::NumPals(){ return Palettes.Length(); }